package com.binge.test8;

import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.engines.SM4Engine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.junit.Test;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.security.Security;

/**
 * ClassName:Sm234
 * Package:com.bin.test8
 * Description:
 *
 * @Author @Bin
 * @Date 2024/5/24-14:49
 * @Version: v1.0
 *
 * 实现:
 * 1.maven依赖:
 * <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk18on -->
 *         <dependency>
 *             <groupId>org.bouncycastle</groupId>
 *             <artifactId>bcprov-jdk18on</artifactId>
 *             <version>1.78.1</version>
 *         </dependency>
 * 2. 以下可抽取为util
 * 3.hibernate 插件或者逻辑切入
 *
 */
public class Sm234 {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }



    @Test
    public void testSm3() {
        //hmac-sm3摘要算法

        SM3Digest digest = new SM3Digest();
        byte[] data = "Hello, SM3!".getBytes();
        digest.update(data, 0, data.length);

        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);

        System.out.println("Hash: " + Hex.toHexString(hash));
    }


    /*
     * hmac-sm3摘要算法
     *  原明文采用此算法算出摘要值,key保存在服务中
     *  落库新加字段或者与原字段融合,以特殊字符分割
     *  出库,解密后,原文加key计算摘要与数据库比对
     * */

    @Test
    public  void hmacSM3Test() {
        try {
            String data = "Hello, World!";
            String key = "mysecretkey";
            String digest = hmacSM3Digest(data, key);
            System.out.println("HMAC-SM3 Digest: " + digest);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /*
    * sm3算法
    * 关键字段采用此算法算出密值,存储在db中
    * 查询时解密,调用hmac-sm3摘要算法与数据库中的摘要比对
    *
    * */

    @Test
    public void testSm4() {
        // 生成 SM4 密钥和 IV
        byte[] key = new byte[16];
        byte[] iv = new byte[16];
        SecureRandom random = new SecureRandom();
        random.nextBytes(key);
        random.nextBytes(iv);

        // 输入数据
        byte[] input = "Hello, SM4!".getBytes();

        // 加密
        byte[] encryptedData = null;
        try {
            encryptedData = encrypt(input, key, iv);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("SM4 Encrypted: " + Hex.toHexString(encryptedData));

        // 解密
        byte[] decryptedData = null;
        try {
            decryptedData = decrypt(encryptedData, key, iv);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        System.out.println("SM4 Decrypted: " + new String(decryptedData));
    }

    public  byte[] encrypt(byte[] data, byte[] key, byte[] iv) throws Exception {
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new SM4Engine()));
        CipherParameters params = new ParametersWithIV(new KeyParameter(key), iv);
        cipher.init(true, params);

        return processCipher(cipher, data);
    }

    public  byte[] decrypt(byte[] data, byte[] key, byte[] iv) throws Exception {
        PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new SM4Engine()));
        CipherParameters params = new ParametersWithIV(new KeyParameter(key), iv);
        cipher.init(false, params);

        return processCipher(cipher, data);
    }

    private  byte[] processCipher(PaddedBufferedBlockCipher cipher, byte[] input) throws Exception {
        byte[] output = new byte[cipher.getOutputSize(input.length)];
        int len = cipher.processBytes(input, 0, input.length, output, 0);
        len += cipher.doFinal(output, len);
        byte[] result = new byte[len];
        System.arraycopy(output, 0, result, 0, len);
        return result;
    }


    public static String hmacSM3Digest(String data, String key) throws Exception {
        Mac mac = Mac.getInstance("HMAC-SM3", "BC");
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HMAC-SM3");
        mac.init(secretKeySpec);

        byte[] bytes = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        return new String(Hex.encode(bytes));
    }



}
